﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using ConsoleCmdProc;

namespace ConsoleCmdTest
{
    /// <summary>
    /// Summary description for UnitTest1
    /// </summary>
    [TestClass]
    public class UnitTest1
    {
        public UnitTest1()
        {
            //
            // TODO: Add constructor logic here
            //
        }

        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        private CommandLine _cmdLineProc;

        #region Additional test attributes
        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestInitialize to run code before running each test 
        [TestInitialize()]
        public void MyTestInitialize() 
        {
            _cmdLineProc = new CommandLine(true);
            _cmdLineProc.DefineOption("o1", "option 1", true, true);
            _cmdLineProc.DefineOption("o2", "option 2", true, false);
            _cmdLineProc.DefineOption("o3", "option 3", false, true, "def3");
            _cmdLineProc.DefineOption("o4", "option 4", false, false, "def4");
            _cmdLineProc.DefineFlag("f1", "flag 1", true);
            _cmdLineProc.DefineFlag("f2", "flag 2", false);
        }
        //
        // Use TestCleanup to run code after each test has run
        // [TestCleanup()]
        // public void MyTestCleanup() { }
        //
        #endregion

        [TestMethod]
        public void NoArgs()
        {
            bool suc = _cmdLineProc.LoadArguments(new string[] { });
            Assert.IsFalse(suc);
        }

        [TestMethod]
        public void TestHelp()
        {
            bool suc = _cmdLineProc.LoadArguments(new string[] { "/h" });
            Assert.IsFalse(suc);
        }

        [TestMethod]
        public void TestAllOptions()
        {
            bool suc = _cmdLineProc.LoadArguments(new string[] { "/o1=xxx", "/o2=yyy", "/o3=zzz", "/o4=www", "/f1", "/f2" });
            Assert.IsTrue(suc);
            Assert.AreEqual("xxx", _cmdLineProc.GetOptionValue("o1")[0]);
            Assert.AreEqual("yyy", _cmdLineProc.GetOptionValue("o2")[0]);
            Assert.AreEqual("zzz", _cmdLineProc.GetOptionValue("o3")[0]);
            Assert.AreEqual("www", _cmdLineProc.GetOptionValue("o4")[0]);
            Assert.IsTrue(_cmdLineProc.GetFlagValue("f1"));
            Assert.IsTrue(_cmdLineProc.GetFlagValue("f2"));
        }

        [TestMethod]
        public void TestMissing()
        {
            bool suc = _cmdLineProc.LoadArguments(new string[] { "/o1=xxx", "/f1", "/f2" });
            Assert.IsFalse(suc);

            suc = _cmdLineProc.LoadArguments(new string[] { "/o1=xxx", "/o2=yyy", "/f2" });
            Assert.IsFalse(suc);

            suc = _cmdLineProc.LoadArguments(new string[] { "/o3=zzz", "/f2" });
            Assert.IsFalse(suc);
        }

        [TestMethod]
        public void TestDuplicate()
        {
            bool suc = _cmdLineProc.LoadArguments(new string[] { "/o1=xxx", "/o2=yyy", "/o3=zzz", "/o4=www", "/f1", "/f2", "/o1=xxx", "/o1=xxx", "/o3=zzz" });
            Assert.IsTrue(suc);
            Assert.AreEqual(3, _cmdLineProc.GetOptionValue("o1").Count);
            Assert.AreEqual(2, _cmdLineProc.GetOptionValue("o3").Count);

            suc = _cmdLineProc.LoadArguments(new string[] { "/o1=xxx", "/o2=yyy", "/o3=zzz", "/o4=www", "/f1", "/f2", "/o2=xxx", "/o2=xxx", "/o4=zzz", "/f1" });
            Assert.IsFalse(suc);
        }

        [TestMethod]
        public void TestMalformed()
        {
            bool suc = _cmdLineProc.LoadArguments(new string[] { "-o3=zzz", "/o1f2", "/o2 = xxx" });
            Assert.IsFalse(suc);
        }

        [TestMethod]
        public void TestUndefined()
        {
            bool suc = _cmdLineProc.LoadArguments(new string[] { "/o5=zzz", "/f3" });
            Assert.IsFalse(suc);
        }

        [TestMethod]
        public void TestByArgAdd()
        {
            CommandLine cmd = new CommandLine();
            cmd.DefineOption("f", "input file", true, false);
            cmd.DefineFlag("d", "debug on", false);

            cmd.AddArgument("/f=test.jpg");
            bool suc = cmd.LoadArguments();
            Assert.IsTrue(suc);

            List<string> opt1 = cmd.GetOptionValue("f");
            Assert.AreEqual("test.jpg", opt1[0]);
        }

        [TestMethod]
        public void TestArgChar()
        {
            CommandLine cmd = new CommandLine();
            cmd.SetArgChar("-");
            cmd.DefineOption("f", "input file", true, false);
            cmd.DefineFlag("d", "debug on", false);

            bool suc = cmd.LoadArguments(new string[] { "-f=test.jpg", "-d" });
            Assert.IsTrue(suc);

            List<string> opt1 = cmd.GetOptionValue("f");
            Assert.AreEqual("test.jpg", opt1[0]);
        }

        [TestMethod]
        [ExpectedException(typeof(Exception))]
        public void TestDefaultNotSet()
        {
            CommandLine cmd = new CommandLine();
            cmd.DefineOption("a", "aaa", true, true);
            cmd.DefineOption("b", "bbb", false, true);
            Assert.Fail();
        }

        [TestMethod]
        public void TestDefaultValues()
        {
            CommandLine cmd = new CommandLine();
            cmd.DefineOption("a", "aaa", true, true);
            cmd.DefineOption("b", "bbb", false, true, "10");
            cmd.DefineOption("c", "ccc", true, true, "15");
            cmd.DefineOption("d", "ddd", false, true, "20");
            cmd.DefineOption("e", "eee", false, true, "30");

            cmd.LoadArguments(new string[]{"/a=5", "/b=15", "/c=18"});

            Assert.AreEqual(5, Convert.ToInt32(cmd.GetOptionValue("a").ElementAt(0)));
            Assert.AreEqual(15, Convert.ToInt32(cmd.GetOptionValue("b").ElementAt(0)));
            Assert.AreEqual(18, Convert.ToInt32(cmd.GetOptionValue("c").ElementAt(0)));
            Assert.AreEqual(20, Convert.ToInt32(cmd.GetOptionValue("d").ElementAt(0)));
            Assert.AreEqual(30, Convert.ToInt32(cmd.GetOptionValue("e").ElementAt(0)));
        }
    }
}
